package  de.tum.softwarengineering1.ws201112.team11.sudoku.model;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JOptionPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

import de.tum.softwarengineering1.ws201112.team11.sudoku.gui.SudokuView;
import de.tum.softwarengineering1.ws201112.team11.sudoku.logic.BackTrackingSolver;
import de.tum.softwarengineering1.ws201112.team11.sudoku.logic.BruteForceSolver;
import de.tum.softwarengineering1.ws201112.team11.sudoku.logic.RandomizedSolver;
import de.tum.softwarengineering1.ws201112.team11.sudoku.strategy.EasyDifficulty;
import de.tum.softwarengineering1.ws201112.team11.sudoku.strategy.HardDifficulty;
import de.tum.softwarengineering1.ws201112.team11.sudoku.strategy.MediumDifficulty;
import de.tum.softwarengineering1.ws201112.team11.sudoku.util.DifficultyContext;
import de.tum.in.softwareengineering1.ws201112.team11.gameframework.base.*;

public class SudokuController implements 
	TableModelListener, Observer 
{
    private static SudokuBoard board;
    private static SudokuView view;

    private boolean autoEvent = false;

    public enum Strategies {
    	RANDOMIZED, BRUTE_FORCE, BACK_TRACKING
    }

    Strategies currentStrategies = null;

    public SudokuController() {
	board = new SudokuBoard();
	
	
	//*** Strategy Pattern *//
	DifficultyContext context = DifficultyContext.getDifficultyContext();
	
	IDifficulty easy = new EasyDifficulty();
	IDifficulty medium = new MediumDifficulty();
	IDifficulty hard = new HardDifficulty();
	
	context.setDifficulty(hard);
	//*******************//
	
	
	board.printBoard();
	view = new SudokuView(board, this);
	board.addObserver(view);
	view.addWindowListener(new WindowAdapter() {
	    @Override
	    public void windowClosing(WindowEvent e) {
		super.windowClosing(e);
		System.exit(0);
	    }
	});
	board.newBoard();
    }

    public void setStrategyChoice(Strategies choice) {
	switch (choice) {
	case RANDOMIZED:
	    board.setSolver(new RandomizedSolver());
	    break;
	case BRUTE_FORCE:
	    board.setSolver(new BruteForceSolver());
	    break;
	case BACK_TRACKING:
	    board.setSolver(new BackTrackingSolver());
	    break;
	}

    }



    @Override
    public void tableChanged(TableModelEvent e) 
    {
		if (autoEvent) {
		    return;
		}

		if (!(e.getSource() instanceof TableModel))
		    return;
		int row = e.getFirstRow();
		int col = e.getColumn();
		TableModel viewMod = (TableModel) e.getSource();
	
		Object valObj = viewMod.getValueAt(row, col);
		// System.out.println("Reached. " + valObj);
		// if (valObj != null && valObj instanceof Integer)
		// // TODO: is an event occurring after a board change from the model?
		// return;
	
		assert valObj != null && valObj instanceof Integer : "Was:"
			+ valObj.getClass();
	
		int newValue = (Integer) valObj;
	
		boolean result = board.setValue(newValue, row, col);
		System.out.println(result);
		autoEvent = true;
		if (!result) {
		    viewMod.setValueAt(board.getValue(row, col), row, col);
	
		} else {
		    if (board.isSolved()) {
			JOptionPane
				.showMessageDialog(view,
					"Congratulations!\nYou solved it. Or did you cheat? :'(");
		    }
		}
		autoEvent = false;
    }

    @Override
    public void update(Observable arg0, Object arg1) {
    }

}
